//
// Copyright (c) 2013, GLX.ME All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//     Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//     Neither the name of the GLX.ME nor the names of its contributors
// may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

//
// WWW: http://glx.me/
//

#include <tcl.h>
#include <stack>
#include <string>
#include <iostream>
#include <time.h>

namespace glx {

	template <typename type>
	class stack: public std::stack<type> {
	public:
		stack() {
			srand(time(NULL));
			_id = rand();
		}
		int id() {
			return _id;
		}
	private:
		int _id;
	}; // "class stack" ends.

	static glx::stack<std::string> staticStack;
	extern "C" int tclStack(ClientData data, Tcl_Interp * interp,
		int argc, char * argv[]) {
		std::string info = "Usage: stack ?push $value? ?pop? ?top?"
			" ?empty? ?size? ?swap? ?emplace? ?id?";
		if (argc == 3) {
			if (std::string(argv[1]) == std::string("push")) {
				int oldsize = staticStack.size();
				staticStack.push(argv[2]);
				int newsize = staticStack.size();
				if (newsize-oldsize == 1) info = "true";
				else info = "false";
			} else if (std::string(argv[1]) == std::string("emplace")) {
				int oldsize = staticStack.size();
				staticStack.emplace(argv[2]);
				int newsize = staticStack.size();
				if (newsize-oldsize == 1) info = "true";
				else info = "false";
			} // else info will hold the default information.
		} else if (argc == 2) {
			if (std::string(argv[1]) == std::string("top")) {
				if (staticStack.empty()) info = "empty";
				else info = staticStack.top();
			} else if (std::string(argv[1]) == std::string("pop")) {
				if (staticStack.empty()) info = "false";
				else {
					int oldsize = staticStack.size();
					staticStack.pop();
					int newsize = staticStack.size();
					if (oldsize-newsize == 1) info = "true";
					else info = "false";
				}
			} else if (std::string(argv[1]) == std::string("empty")) {
				if (staticStack.empty()) info = "true";
				else info = "false";
			} else if (std::string(argv[1]) == std::string("size")) {
				info = std::to_string(staticStack.size());
			} else if (std::string(argv[1]) == std::string("swap")) {
				info = "swap is not implemented because there is only one static stack currently.";
			} else if (std::string(argv[1]) == std::string("id")) {
				info = std::to_string(staticStack.id());
			} // else info will hold the default information.
		} else if (argc >= 4) {
			if (std::string(argv[1]) == std::string("emplace")) {
				info = "[stack emplace ?multi strings?] is not implemented.";
			} // else info will hold the default information.
		} // else info will hold the default information.
		Tcl_SetResult(interp, (char *)(info.c_str()), TCL_VOLATILE);
		return TCL_OK;
	}

	void parseTclStack(Tcl_Interp * interp) {
		Tcl_CreateCommand(interp, "stack",
			(Tcl_CmdProc *)(glx::tclStack),
			0, 0);
	}

} // "namespace glx" ends.

int main(int argc, char * argv[]) {
	glx::stack<std::string> stack;
	if (argc == 1) {
		const char * info[] = {"Hello", "World", "C++/Tcl/Tk", "FreeBSD"};
		for (const std::string & str: info) {
			stack.push(str);
		}
		while (!stack.empty()) {
			std::cout << stack.top() << std::endl;
			stack.pop();
		}
		std::cout << "You can run a tcl script with "
			<< argv[0]
			<< " script.tcl"
			<< std::endl;
	} else if (argc == 2) {
		Tcl_Interp * interp = Tcl_CreateInterp();
		glx::parseTclStack(interp);
		Tcl_EvalFile(interp, argv[1]);
		Tcl_DeleteInterp(interp);
	}
	return 0;
}


